package io.github.kimmking.kkconfig.value;

import cn.kimmking.utils.FieldUtils;
import io.github.kimmking.kkconfig.util.PlaceholderHelper;
import lombok.Data;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.context.event.EventListener;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.util.List;

/**
 * Description for this class.
 *
 * @Author : kimmking(kimmking@apache.org)
 * @create 2024/4/19 00:48
 */

@Data
public class SpringValueProcessor implements BeanPostProcessor, BeanFactoryAware {

    static final MultiValueMap<String, SpringValue> VALUE_HOLDER = new LinkedMultiValueMap<>();
    static final PlaceholderHelper helper = PlaceholderHelper.getInstance();

    private BeanFactory beanFactory;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName){
        FieldUtils.findAnnotatedField(bean.getClass(), Value.class).forEach(
                field -> {
                    Value value = field.getAnnotation(Value.class);
                    helper.extractPlaceholderKeys(value.value()).forEach(key -> {
                        SpringValue springValue = new SpringValue(bean, beanName, key, value.value(), field);
                        VALUE_HOLDER.add(key, springValue);
                    });
                }
        );
        return bean;
    }

    @EventListener
    public void onChange(EnvironmentChangeEvent event) {
        event.getKeys().forEach( k -> {
            System.out.println(" [KKCONFIG]===>> EventListener onChange: " + k + "-> ? ");
            List<SpringValue> springValues = SpringValueProcessor.VALUE_HOLDER.get(k);
            if (springValues == null || springValues.isEmpty()) {
                return;
            }
            springValues.forEach(springValue -> {
                System.out.println(" [KKCONFIG]===>> springvalue[" + springValue.getPlaceholder()+ "] for update");
                try {
                    Object value = PlaceholderHelper.getInstance()
                            .resolvePropertyValue((ConfigurableBeanFactory) beanFactory, springValue.getBeanName(), springValue.getPlaceholder());
                    System.out.println(" [KKCONFIG]====>>> update: set field[" + springValue.getBeanName()
                            + "." + springValue.getField().getName() + "] value[" + value + "]");
                    springValue.getField().setAccessible(true);
                    springValue.getField().set(springValue.getBean(), value);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            });
        });
    }
}
